package org.nf.chat.websocket;

import com.google.gson.Gson;
import org.nf.chat.model.Message;
import org.nf.chat.model.User;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * configurator属性用于指定握手配置类的class
 */
@ServerEndpoint(value = "/ws/connect", configurator = WebSocketHandshake.class)
public class WebSocketServer {

    /**
     * 用户列表，Session表示每一个用户的websocket会话连接对象
     * key是用户的id，value是websocket的连接会话对象
     */
    private static Map<String, Session> users = new HashMap<>();

    /**
     * 连接打开方法，每当客户端连接到服务器时会执行此方法
     * 容器会为每一个客户端创建一个唯一的Session实例
     * ，这样在连接的时候就可以将所有用户的session保存到用户列表中
     * 方便后面进行消息的推送
     */
    @OnOpen
    public void onOpen(Session session) {
        //从当前用户会话中获取属性信息（map，类似于websocket的作用域）
        User user = (User)session.getUserProperties().get("user");
        //保存到用户列表
        users.put(user.getId(), session);
    }

    /**
     * 关闭连接
     */
    @OnClose
    public void onClose(Session session) {
        User user = (User) session.getUserProperties().get("user");
        System.out.println(user.getUserName() + "已离线");
        //从用户列表中移除当前用户的session
        users.remove(session);
    }

    /**
     * 接收客户端的消息，并将消息转发给所有人
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        //判断是否是心跳检查
        if("ping".equals(message)) {
            return;
        }
        //当前登录的用户就是发送人
        User sendUser = (User) session.getUserProperties().get("user");
        Message msg = new Message();
        msg.setSendUser(sendUser.getUserName());
        msg.setMessage(message);
        //将消息发送给所有人
        //先将msg序列化成json字符串
        String json = new Gson().toJson(msg);
        //群发
        users.forEach((id, sess) -> {
            try {
                //从session中获取远程连接对象进行发送
                sess.getBasicRemote().sendText(json);
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException("发送失败", e);
            }
        });
    }
}
